package viper.main;


/**
 * @author Kevin Sin
 * 
 * Revision number: 3
 * Date created: 3/21/10
 * Date of Last Back-up on SVN: 3/21/10
 * 
 * <p>This class is used to standardize the VIPER header constants.
 * We also have convenience methods to make the packets w/ specific
 * headers for setup, relaying, and receiving.
 */
public class ViperHeader {
	public static final byte RELAY = 1;
	public static final byte RECEIVE = 2;
	public static final byte CALL_SETUP = 3;
	public static final byte STATISTICS = 4;
	
	public static final byte SETUP_MAKE_CALL = 31;
	public static final byte SETUP_ACCEPT_CALL = 32;
	public static final byte SETUP_REJECT_CALL = 33;
	public static final byte SETUP_END_CALL = 34;
	public static final byte SETUP_CANCEL_CALL = 35;
	public static final byte SETUP_ERROR = 36;
	
	public static final byte CODE_232 = 41;
	public static final byte CODE_364 = 42;
	public static final byte CODE_111 = 43;//use 1 relay
	public static final byte CODE_101 = 44;//direct to receiver; no relay used
	
	public static final byte DIV_A_1 = 51;
	public static final byte DIV_A_2 = 52;
	public static final byte DIV_A_3 = 53;	
	
	public static final byte DIV_B_1 = 61;
	public static final byte DIV_B_2 = 62;
	public static final byte DIV_B_3 = 63;
	public static final byte DIV_B_4 = 64;
	public static final byte DIV_B_5 = 65;
	public static final byte DIV_B_6 = 66;	
	
	
	public static byte[] makeCallSetupPacket(byte setupType, byte[] payload)
	{
		int length = 0;
		if(payload!=null)
			length = payload.length;
		byte[] bytes = new byte[length+2];
		bytes[0] = CALL_SETUP;
		bytes[1] = setupType;
		if(length>0)
			System.arraycopy(payload, 0, bytes, 2, length);
		return bytes;
	}
	public static byte[] makeCallStatisticsPacket(byte[] payload)
	{
		int length = 0;
		if(payload!=null)
			length = payload.length;
		byte[] bytes = new byte[length+1];
		bytes[0] = STATISTICS;
		if(length>0)
			System.arraycopy(payload, 0, bytes, 1, length);
		return bytes;
	}
	
	public static byte[] makeCallReceivePacket(byte[] timeBytes, byte packetType, byte[] payload)
	{
		int length = 0;
		if(payload!=null)
			length = payload.length;
		byte[] bytes = new byte[length+10];
		bytes[0] = RECEIVE;
		bytes[1] = timeBytes[0];
		bytes[2] = timeBytes[1];
		bytes[3] = timeBytes[2];
		bytes[4] = timeBytes[3];
		bytes[5] = timeBytes[4];
		bytes[6] = timeBytes[5];
		bytes[7] = timeBytes[6];
		bytes[8] = timeBytes[7];
		bytes[9] = packetType;
		if(length>0)
			System.arraycopy(payload, 0, bytes, 10, length);
		return bytes;
	}
	
	public static byte[] makeCallRelayPacket(byte[] calleeAddrBytes, byte[] timeBytes, byte packetType, byte[] payload)
	{
		/* Format of packet to be sent for (1,1,1) case
		 * <Relay (1 byte)> <RX IP Addr (4 byte)> <Seq # (1 byte)> <Pkt Type (1 byte)> <Data>
		 */
		int length = 0;
		if(payload!=null)
			length = payload.length;
		byte[] bytes = new byte[length+14];
		
		bytes[0] = RELAY;
		System.arraycopy(calleeAddrBytes, 0, bytes, 1, 4);
		bytes[5] = timeBytes[0];
		bytes[6] = timeBytes[1];
		bytes[7] = timeBytes[2];
		bytes[8] = timeBytes[3];
		bytes[9] = timeBytes[4];
		bytes[10] = timeBytes[5];
		bytes[11] = timeBytes[6];
		bytes[12] = timeBytes[7];
		bytes[13] = packetType;

		if(length>0)
			System.arraycopy(payload, 0, bytes, 14, length);
		return bytes;
	}
	
	public static byte[] getPayloadFromSetupPacket(byte[] packet)
	{
		int length = packet.length;
		if(length>2)
		{
			byte[] payload = new byte[length-2];
			System.arraycopy(packet, 2, payload, 0, length-2);
			return payload;
		}
		else
		{
			return null;
		}
	}
	public static byte[] getPayloadFromStatisticsPacket(byte[] packet)
	{
		int length = packet.length;
		if(length>1)
		{
			byte[] payload = new byte[length-1];
			System.arraycopy(packet, 1, payload, 0, length-1);
			return payload;
		}
		else
		{
			return null;
		}
	}
	/* @param byte[] packet
	 * @return byte[] payload
	 *
	 * Description:
	 * Removes the <Node Type (1 byte)> field from the header returning a byte[] with the
	 * format <Seq # (1 byte)> <Pkt Type (1 byte)> <Data>
	 */
	public static byte[] getPayloadFromReceivePacket(byte[] packet)
	{
		int length = packet.length;
		if(length>1)
		{
			byte[] payload = new byte[length-1];
			System.arraycopy(packet, 1, payload, 0, length-1);
			return payload;
		}
		else
		{
			return null;
		}
	}
	
	//-----------------serializing methods-------------------
	public static final byte[] intToByteArray(int value) {
        return new byte[] {
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value};
	}

	public static final int byteArrayToInt(byte [] b) {
        return (b[0] << 24)
                + ((b[1] & 0xFF) << 16)
                + ((b[2] & 0xFF) << 8)
                + (b[3] & 0xFF);
	}
	
	public static final byte[] longToByteArray(long value) {
        return new byte[] {
        		(byte)(value >>> 56),
                (byte)(value >>> 48),
                (byte)(value >>> 40),
                (byte)(value >>> 32),
                (byte)(value >>> 24),
                (byte)(value >>> 16),
                (byte)(value >>> 8),
                (byte)value};
	}

	public static final long byteArrayToLong(byte [] b) {
        return (b[0] << 56)
                + ((b[1] & 0xFF) << 48)
                + ((b[2] & 0xFF) << 40)
                + ((b[3] & 0xFF) << 32)
                + ((b[4] & 0xFF) << 24)
                + ((b[5] & 0xFF) << 16)
                + ((b[6] & 0xFF) << 8)
                + (b[7] & 0xFF);
	}
	//---------------------------------------------------------
	
	public static void main(String[] args)
	{
		long my = (long)12240120;
		System.out.println(my);
		Long as = new Long(my);
		long my2 = as;
		System.out.println(my2);
	}
}
